import { writeFile, mkdir } from 'fs/promises'
import { join } from 'path'

export enum LogLevel {
  DEBUG = 0,
  INFO = 1,
  WARN = 2,
  ERROR = 3
}

interface LogEntry {
  timestamp: string
  level: LogLevel
  message: string
  context?: Record<string, any>
  error?: Error
}

class Logger {
  private logLevel: LogLevel = LogLevel.INFO
  private logDir = './logs'

  constructor() {
    this.ensureLogDir()
  }

  private async ensureLogDir() {
    try {
      await mkdir(this.logDir, { recursive: true })
    } catch (error) {
      console.error('Failed to create log directory:', error)
    }
  }

  setLevel(level: LogLevel) {
    this.logLevel = level
  }

  debug(message: string, context?: Record<string, any>) {
    this.log(LogLevel.DEBUG, message, context)
  }

  info(message: string, context?: Record<string, any>) {
    this.log(LogLevel.INFO, message, context)
  }

  warn(message: string, context?: Record<string, any>) {
    this.log(LogLevel.WARN, message, context)
  }

  error(message: string, error?: Error, context?: Record<string, any>) {
    this.log(LogLevel.ERROR, message, context, error)
  }

  private async log(
    level: LogLevel, 
    message: string, 
    context?: Record<string, any>, 
    error?: Error
  ) {
    if (level < this.logLevel) return

    const entry: LogEntry = {
      timestamp: new Date().toISOString(),
      level,
      message,
      context,
      error
    }

    // 控制台输出
    this.logToConsole(entry)

    // 文件输出
    await this.logToFile(entry)
  }

  private logToConsole(entry: LogEntry) {
    const levelNames = ['DEBUG', 'INFO', 'WARN', 'ERROR']
    const colors = ['\x1b[36m', '\x1b[32m', '\x1b[33m', '\x1b[31m']
    const reset = '\x1b[0m'

    const color = colors[entry.level]
    const levelName = levelNames[entry.level]
    
    console.log(
      `${color}[${entry.timestamp}] ${levelName}:${reset} ${entry.message}`
    )

    if (entry.context) {
      console.log('Context:', entry.context)
    }

    if (entry.error) {
      console.error('Error:', entry.error)
    }
  }

  private async logToFile(entry: LogEntry) {
    try {
      const date = new Date().toISOString().split('T')[0]
      const filename = join(this.logDir, `${date}.log`)
      
      const logLine = JSON.stringify(entry) + '\n'
      await writeFile(filename, logLine, { flag: 'a' })
    } catch (error) {
      console.error('Failed to write log file:', error)
    }
  }
}

export const logger = new Logger()
